package com.hifar.utils;

import com.tssk.kylx.fw.json.JsonUtils;
import com.tssk.kylx.fw.utils.bean.BusiRequest;
import com.tssk.kylx.fw.utils.bean.BusiResponse;
import com.tssk.kylx.fw.utils.lang.DateUtils;
import com.tssk.kylx.fw.utils.lang.StringUtils;
import org.springframework.util.Assert;

import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

/**
 * @author zhuWeiWei
 * @description 工具箱
 * @date 2024/12/5 11:21
 */
public class ToolKit {
    /**
     * 序号补0
     * @param no
     * @param digitNum
     * @return
     */
    public static String supplementZero(String no, int digitNum) {
        if (no == null) {
            throw new IllegalArgumentException("no不能为空!");
        }
        StringBuilder noBuilder = new StringBuilder();
        if (no.length() >= digitNum) {
            return no;
        }
        int diffNum = digitNum - no.length();
        for (int i = 0; i < diffNum; i++) {
            noBuilder.append("0");
        }
        noBuilder.append(no);
        return noBuilder.toString();
    }

    /**
     * 驼峰命名 改下划线命名
     *
     * @param camelCaseStr
     * @return
     */
    public static String toUnderScoreCase(String camelCaseStr) {
        if (camelCaseStr == null) {
            throw new IllegalArgumentException("camelCaseStr不能为空!");
        }
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < camelCaseStr.length(); i++) {
            char c = camelCaseStr.charAt(i);
            if (Character.isUpperCase(c)) {
                if (i > 0) {
                    builder.append('_');
                }
                builder.append(Character.toLowerCase(c));
            } else {
                builder.append(c);
            }
        }
        return builder.toString();
    }

    /**
     * Date 转 LocalDateTime
     * @param date
     * @return
     */
    public static LocalDateTime convertToDate(Date date) {
        if (date == null) {
            throw new IllegalArgumentException("date不能为空!");
        }
        // 将 Date 转换为 Instant
        Instant instant = date.toInstant();
        // 指定时区（例如：使用系统默认时区）
        ZoneId zoneId = ZoneId.systemDefault();
        // 将 Instant 转换为 LocalDateTime
        return LocalDateTime.ofInstant(instant, zoneId);
    }

    public static BigDecimal minBigDecimal(BigDecimal a, BigDecimal b) {
        if (a == null && b == null) {
            return null;
        } else if (a == null) {
            return b;
        } else if (b == null) {
            return a;
        }
        return a.compareTo(b) > 0 ? b : a;
    }

    public static BigDecimal minBigDecimal(Integer scale, BigDecimal... arr) {
        BigDecimal tempBigDecimal = null;
        for (BigDecimal temp : arr) {
            if (tempBigDecimal == null) {
                tempBigDecimal = temp;
            } else {
                tempBigDecimal = ToolKit.minBigDecimal(tempBigDecimal, temp);
            }
        }
        if (scale != null && tempBigDecimal != null) {
            return tempBigDecimal.setScale(scale, RoundingMode.HALF_UP);
        }
        return tempBigDecimal;
    }

    public static BigDecimal minBigDecimal(BigDecimal... arr) {
        return minBigDecimal(null, arr);
    }

    public static BigDecimal maxBigDecimal(Integer scale, BigDecimal... arr) {
        BigDecimal tempBigDecimal = null;
        for (BigDecimal temp : arr) {
            if (tempBigDecimal == null) {
                tempBigDecimal = temp;
            } else {
                tempBigDecimal = ToolKit.maxBigDecimal(tempBigDecimal, temp);
            }
        }
        if (scale != null && tempBigDecimal != null) {
            return tempBigDecimal.setScale(scale, RoundingMode.HALF_UP);
        }
        return tempBigDecimal;
    }

    public static BigDecimal maxBigDecimal(BigDecimal... arr) {
        return maxBigDecimal(null, arr);
    }

    public static BigDecimal maxBigDecimal(BigDecimal a, BigDecimal b) {
        if (a == null && b == null) {
            return null;
        } else if (a == null) {
            return b;
        } else if (b == null) {
            return a;
        }
        return a.compareTo(b) > 0 ? a : b;
    }

    public static String getFileSuffix(String fileName) {
        if (StringUtils.isEmpty(fileName)) {
            throw new RuntimeException("fileName不能为空!");
        }
        int lastIndexOf = fileName.lastIndexOf(".");
        if (lastIndexOf < 0) {
            throw new RuntimeException("不正确的文件名!");
        }
        return fileName.substring(lastIndexOf);
    }


    /**
     * 获取当前结束时间
     * @return
     */
    public static Date dayFinallyDay() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 23); // 小时
        calendar.set(Calendar.MINUTE, 59); // 分钟
        calendar.set(Calendar.SECOND, 59); // 秒
        calendar.set(Calendar.MILLISECOND, 999); // 毫秒
        return calendar.getTime();
    }


    public static Date dayFirst() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0); // 小时
        calendar.set(Calendar.MINUTE, 0); // 分钟
        calendar.set(Calendar.SECOND, 0); // 秒
        calendar.set(Calendar.MILLISECOND, 0); // 秒
        return calendar.getTime();
    }

    /**
     * 当前日期偏移几天
     *
     * @param count
     * @return
     */
    public static Date dateOffset(int count) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_YEAR, count);
        return calendar.getTime();
    }


    public static String generateInSql(String field, Integer size, Integer startNum) {
        Assert.isTrue(size > 0, "生成inSql数量不能小于等于0");
        StringBuilder inBuilder = new StringBuilder();
        inBuilder.append("\t");
        inBuilder.append(field).append(" in ");
        inBuilder.append("(");
        for (Integer integer = 0; integer < size; integer++) {
//            {0}
            inBuilder.append("{").append(integer + startNum).append("}");
            if (integer < size - 1) {
                inBuilder.append(",");
            }
        }
        inBuilder.append(")");
        return inBuilder.toString();
    }

    public static BigDecimal diffDateHour(Date startDate, Date endDate) {
        return diffDateHour(startDate, endDate, 2, RoundingMode.HALF_UP);
    }

    public static BigDecimal diffDateHour(Date startDate, Date endDate, int scale) {
        return diffDateHour(startDate, endDate, scale, RoundingMode.HALF_UP);
    }

    public static BigDecimal diffDateHour(Date startDate, Date endDate, int scale, RoundingMode roundingMode) {
        if (Objects.isNull(startDate) || Objects.isNull(endDate)) {
            return BigDecimal.ZERO;
        }
        if (startDate.after(endDate)) {
            return BigDecimal.ZERO;
        }
        long startTime = startDate.getTime();
        long endTime = endDate.getTime();
        return new BigDecimal(endTime - startTime).divide(new BigDecimal(60 * 60 * 1000), scale, roundingMode);
    }


    /**
     * 写文件（带编码参数）
     *
     * @param file 文件
     * @param content 内容
     * @param encoding 编码格式
     */
    public static void writeFile(File file, String content, String encoding) {
        try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), encoding))) {
            out.append(content);
            System.out.println("使用编码 " + encoding + " 写入文件: " + file.getName() + ", 内容长度: " + content.length());
        } catch (Exception e) {
            System.err.println("使用编码 " + encoding + " 写入文件失败: " + file.getName() + ", 错误: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 写文件
     *
     * @param file
     * @param content
     */
    public static void writeFile(File file, String content) {
        try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
            out.append(content);
            System.out.println("使用默认UTF-8编码写入文件: " + file.getName() + ", 内容长度: " + content.length());
        } catch (Exception e) {
            System.err.println("写入文件失败: " + file.getName() + ", 错误: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 读取文件（带编码参数）
     *
     * @param file 文件
     * @param encoding 指定编码
     * @return 文件内容
     */
    public static String readFile(File file, String encoding) {
        try (InputStream in = new FileInputStream(file);
             ByteArrayOutputStream out = new ByteArrayOutputStream()) {

            byte[] bytes = new byte[8192];
            int len;
            while ((len = in.read(bytes)) != -1) {
                out.write(bytes, 0, len);
            }
            byte[] byteArray = out.toByteArray();

            String content = new String(byteArray, encoding);
            System.out.println("使用指定编码 " + encoding + " 读取文件: " + file.getName() + ", 内容长度: " + content.length());
            return content;
        } catch (IOException e) {
            System.err.println("使用编码 " + encoding + " 读取文件失败: " + file.getName() + ", 错误: " + e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 读取文件
     *
     * @param file
     * @return
     */
    public static String readFile(File file) {
        try (InputStream in = new FileInputStream(file);
             ByteArrayOutputStream out = new ByteArrayOutputStream()) {

            byte[] bytes = new byte[8192];
            int len;
            while ((len = in.read(bytes)) != -1) {
                out.write(bytes, 0, len);
            }
            byte[] byteArray = out.toByteArray();
            String content = new String(byteArray, "UTF-8");
            System.out.println("使用默认UTF-8编码读取文件: " + file.getName() + ", 内容长度: " + content.length());
            return content;
        } catch (IOException e) {
            System.err.println("读取文件失败: " + file.getName() + ", 错误: " + e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断两个日期是否为同一天
     *
     * @param date1 日期1
     * @param date2 日期2
     * @return 是否为同一天
     */
    public static boolean isSameDay(Date date1, Date date2) {
        if (Objects.isNull(date1) || Objects.isNull(date2)) {
            return false;
        }
        String formatTime1 = DateUtils.formatTime(date1, "yyyyMMdd");
        String formatTime2 = DateUtils.formatTime(date2, "yyyyMMdd");
        return Objects.equals(formatTime1, formatTime2);
    }

    /**
     * @deprecated 方法命名不准确，请使用 {@link #isSameDay(Date, Date)}
     */
    @Deprecated
    public static boolean isValidDate(Date date1, Date date2) {
        return isSameDay(date1, date2);
    }

    /**
     * 计算2个日期相差多少毫秒
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public static Long diffTime(Date startTime, Date endTime) {
        Assert.notNull(startTime, "开始时间不能为空!");
        Assert.notNull(endTime, "结束时间不能为空!");
        Assert.isTrue(!startTime.after(endTime), "结束时间不能小于开始时间!");
        long startTimeL = startTime.getTime();
        long endTimeL = endTime.getTime();
        return endTimeL - startTimeL;
    }

    /**
     * 驼峰命名转下划线命名
     *
     * @param str 驼峰命名
     * @return 下划线
     */
    public static String camelToSnake(String str) {
        if (str == null) {
            throw new IllegalArgumentException("str不能为空!");
        }
        return str.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
    }

    /**
     * 下划线命名转驼峰命名
     *
     * @param str 下划线命名
     * @return
     */
    public static String snakeToCamel(String str) {
        if (str == null) {
            throw new IllegalArgumentException("str不能为空!");
        }
        StringBuilder builder = new StringBuilder();
        boolean capitalizeNext = false;

        for (char c : str.toCharArray()) {
            if (c == '_') {
                capitalizeNext = true;
            } else {
                if (capitalizeNext) {
                    builder.append(Character.toUpperCase(c));
                    capitalizeNext = false;
                } else {
                    builder.append(c);
                }
            }
        }
        return builder.toString();
    }

    public static List<String> splitStr(String str, Integer size) {
        if (str == null) {
            throw new IllegalArgumentException("str不能为空!");
        }
        if (size == null || size <= 0) {
            throw new IllegalArgumentException("size必须大于0!");
        }
        List<String> dataList = new ArrayList<>();
        int beginIndex = 0;
        while (beginIndex < str.length()) {
            int endIndex = Math.min(beginIndex + size, str.length());
            String itemStr = str.substring(beginIndex, endIndex);
            dataList.add(itemStr);
            beginIndex += size;
        }
        return dataList;
    }

    /**
     * 添加日志
     *
     * @param request
     * @param response
     * @param type
     * @param errInfo
     * @param isError
     */
    public static void writeLog(BusiRequest request, BusiResponse response, String type, String errInfo, boolean isError) {
        String basePath = System.getProperty("user.dir");
        String dateText = DateUtils.formatTime(new Date(), "yyyy/MM/dd");
        File logBasePath = new File(String.format("%s/../apiLog/%s", basePath, dateText));
        if (!logBasePath.exists()) {
            logBasePath.mkdirs();
        }
        String fileName = isError ? "error.log" : "info.log";
        File logFile = new File(String.format("%s/%s", logBasePath, fileName));
        try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(logFile, true), "UTF-8"))) {
            StringBuilder infoBuilder = new StringBuilder();
            String writeTime = DateUtils.formatTime(new Date(), "yyyy-MM-dd HH:mm:ss");
            infoBuilder.append(String.format("\n==================%s【%s】参数===========================\n", writeTime, type));
            infoBuilder.append(JsonUtils.toJson(request.getData()));
            if (isError) {
                infoBuilder.append("\n=====================异常信息===========================\n");
                infoBuilder.append(StringUtils.trimNull(errInfo));
            }
            infoBuilder.append("\n==============================返回信息======================================\n");
            infoBuilder.append(JsonUtils.toJson(response));
            infoBuilder.append("\n============================END===================================\n");
            out.write(infoBuilder.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void writeLog(String type, String info, String resultInfo, String errInfo, boolean isError) {
        writeLog("apiLog", type, info, resultInfo, errInfo, isError);
    }


    public static void writeLog(String fileDir, String type, String info, String resultInfo, String errInfo, boolean isError) {
        String basePath = System.getProperty("user.dir");
        String dateText = DateUtils.formatTime(new Date(), "yyyy/MM/dd");
        File logBasePath = new File(String.format("%s/../%s/%s", basePath, fileDir, dateText));
        if (!logBasePath.exists()) {
            logBasePath.mkdirs();
        }
        String fileName = isError ? "error.log" : "info.log";
        File logFile = new File(String.format("%s/%s", logBasePath, fileName));
        try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(logFile, true), "UTF-8"))) {
            StringBuilder infoBuilder = new StringBuilder();
            String writeTime = DateUtils.formatTime(new Date(), "yyyy-MM-dd HH:mm:ss");
            infoBuilder.append(String.format("==================%s【%s】参数===========================\n", writeTime, type));
            infoBuilder.append(info);
            if (isError) {
                infoBuilder.append("\n=====================异常信息===========================\n");
                infoBuilder.append(StringUtils.trimNull(errInfo));
            }
            infoBuilder.append("\n============================返回信息===================================\n");
            infoBuilder.append(StringUtils.trimNull(resultInfo));
            infoBuilder.append("\n============================END===================================\n");
            out.write(infoBuilder.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
